#region Header

// MS codename Velocity Distributed Cache Extensions.
// (c) 2009

#endregion


#region Usings

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

#endregion


namespace Caching.Extensions.Core.Impl
{
    /// <summary>
    /// Local cache performance logger
    /// </summary>
    public class LocalCachePerformanceLogger
    {
        #region Private data 

        private readonly PerformanceCounterCategory m_category;
        private readonly PerformanceCounter m_hitsTotal;
        private readonly PerformanceCounter m_hitsPerSecond;
        private readonly PerformanceCounter m_putsPerSecond;
        private readonly PerformanceCounter m_missesPerSecond;
        private readonly PerformanceCounter m_missesTotal;
        private readonly PerformanceCounter m_removesPerSecond;
        private readonly PerformanceCounter m_totalErrors;
        private readonly PerformanceCounter m_cleanupsTotal;
        private readonly PerformanceCounter m_errorsPerSecond;

        #endregion Private data


        #region ctor 

        /// <summary>
        /// Initializes a new instance of the <see cref="LocalCachePerformanceLogger"/> class.
        /// </summary>
        public LocalCachePerformanceLogger()
        {
            m_category = new PerformanceCounterCategory(LocalCachePerfCounters.CategoryName);

            IEnumerable<PerformanceCounter> counters = m_category.GetCounters();
            m_hitsPerSecond = PerfCounterHelper.GetCounterByName(counters, LocalCachePerfCounters.HitsPerInterval);
            m_hitsTotal = PerfCounterHelper.GetCounterByName(counters, LocalCachePerfCounters.HitsTotal);
            m_putsPerSecond = PerfCounterHelper.GetCounterByName(counters, LocalCachePerfCounters.PutsPerInterval);
            m_missesPerSecond = PerfCounterHelper.GetCounterByName(counters, LocalCachePerfCounters.MissesPerInterval);
            m_missesTotal = PerfCounterHelper.GetCounterByName(counters, LocalCachePerfCounters.MissesTotal);
            m_removesPerSecond = PerfCounterHelper.GetCounterByName(counters, LocalCachePerfCounters.RemovesPerInterval);
            m_cleanupsTotal = PerfCounterHelper.GetCounterByName(counters, LocalCachePerfCounters.CleanupsTotal);
            m_totalErrors = PerfCounterHelper.GetCounterByName(counters, LocalCachePerfCounters.ErrorsTotal);
            m_errorsPerSecond = PerfCounterHelper.GetCounterByName(counters, LocalCachePerfCounters.ErrorsPerSecond);
        }

        #endregion ctor


        #region Counters 

        protected internal PerformanceCounter HitsTotal
        {
            get { return m_hitsTotal; }
        }

        protected internal PerformanceCounter HitsPerSecond
        {
            get { return m_hitsPerSecond; }
        }

        protected internal PerformanceCounter ErrorsTotal
        {
            get { return m_totalErrors; }
        }

        protected internal PerformanceCounter ErrorsPerSecond
        {
            get { return m_errorsPerSecond; }
        }

        protected internal PerformanceCounter MissesPerSecond
        {
            get { return m_missesPerSecond; }
        }

        protected internal PerformanceCounter MissesTotal
        {
            get { return m_missesTotal; }
        }

        protected internal PerformanceCounter RemovesPerSecond
        {
            get { return m_removesPerSecond; }
        }

        protected internal PerformanceCounter PutsPerSecond
        {
            get { return m_putsPerSecond; }
        }

        protected internal PerformanceCounter CleanupsTotal
        {
            get { return m_cleanupsTotal; }
        }

        #endregion Counters


        #region Cache statistics 

        /// <summary>
        /// Cache hit
        /// </summary>
        public void OnCacheHit()
        {
            HitsPerSecond.Increment();
            HitsTotal.Increment();
        }


        /// <summary>
        /// Cache miss
        /// </summary>
        public void OnCacheMiss()
        {
            MissesPerSecond.Increment();
            MissesTotal.Increment();
        }


        /// <summary>
        /// Item Removed from cache
        /// </summary>
        public void OnRemove()
        {
            RemovesPerSecond.Increment();
        }


        /// <summary>
        /// Item added to cache
        /// </summary>
        public void OnAdd()
        {
            PutsPerSecond.Increment();
        }


        /// <summary>
        /// Cache cleanup
        /// </summary>
        public void OnCleanup()
        {
            CleanupsTotal.Increment();
        }


        /// <summary>
        /// Cache error
        /// </summary>
        public void OnError()
        {
            ErrorsTotal.Increment();
            ErrorsPerSecond.Increment();
        }

        #endregion Cache statistics
    }


    /// <summary>
    /// Performance counter helper
    /// </summary>
    public class PerfCounterHelper
    {
        /// <summary>
        /// Gets the counter by name.
        /// </summary>
        /// <param name="counters">The counters.</param>
        /// <param name="counterName">Name of the counter.</param>
        /// <returns>Counter</returns>
        /// <exception cref="InvalidOperationException">If counter with specified name not found</exception>
        public static PerformanceCounter GetCounterByName(IEnumerable<PerformanceCounter> counters, string counterName)
        {
            if (string.IsNullOrEmpty(counterName))
                throw new ArgumentNullException("counterName");

            var counter = counters.SingleOrDefault(c => c.CounterName == counterName);
            if (counter == null)
                throw new InvalidOperationException("Cannot find counter: " + counterName);
            counter.ReadOnly = false;
            return counter;
        }
    }
}